// background.js
console.log('Background script is running...');
import { CryptoJS } from "./crypto-js.min.js"
import { fetchRequest, base64ToBlob, getFromatTime, getBrowserName, setSyncStorage, getSyncStorage, removeSyncStorage, generateImgName  } from './tools.js';


var initData = {
    token: '',
    loadFiles: [],
    t: null,
    processingID: [],
    processingT: null
}
getSyncStorage("fileObj").then(async filesStorage => {
    initData.loadFiles = filesStorage || [];
});

chrome.runtime.onMessage.addListener(async function (request, sender, sendResponse) {
    sendResponse("ok")
    console.log('background:',request);
    initData.loadFiles = await getSyncStorage("fileObj") || [];
    
    if (request.type === 'pageToken') {
        initData.token = request.data;
        setSyncStorage({ "token": initData.token })
        const rq = new RequestQueue();
        if(!initData.processingT){
            await rq.enqueueProcessing();
        }
    }
    if (request.action === 'printFiles') {
        const requestPolicyData = await getRequestPolicy();
        if(!requestPolicyData){
            removeSyncStorage("token");
            return;
        }
        await uploadAllImg(request.data,requestPolicyData);
        const rq = new RequestQueue();
        
        await rq.loadNextEnqueueVideo();
        await rq.enqueueProcessing();
    }
});
class RequestQueue {
    constructor() {
        this.queue = JSON.parse(JSON.stringify(initData.loadFiles)); // 用于存储待处理的任务
        this.maxQueue = false; // 标记队列是否达到最大值
        this.maxQueueLength = 5;
        // this.requestFrequency = 0;
    }
    // 添加任务到队列中
    async enqueueVideo(file){
        if(file){
            const targetFile = initData.loadFiles.find(item=> 
                item.timer == file.timer && item.status === 0
            );
            let fileList = [
                { 'id': file.fileID, 'name': file.name, 'type': file.type },
            ]
            // this.requestFrequency++;

            const res = await saveVideo(file,fileList);
            if(res){
                if(res?.statusInfo?.code == 0){
                    const videoId = res?.data?.id;
                    if(videoId){
                        if(targetFile){
                            targetFile.status = 1;
                            targetFile.videoId = videoId;
                            sendFileDataToPopup();
                        }
                    }else{
                        console.log("videoId error:", videoId);
                    }
                }else if(res?.statusInfo.code == 2400013){
                    // 队列已满
                    this.maxQueue = true;
                }else{
                    // 其他状态
                    console.log(res?.statusInfo.code,res?.statusInfo.message);
                    // console.log("this.requestFrequency:",this.requestFrequency);
                    targetFile.status = -1;
                    sendFileDataToPopup();
                    await this.loadNextEnqueueVideo();
                }
            }else{
                // if(this.requestFrequency >= 3){
                    if(targetFile){
                        targetFile.status = -1;
                    }
                    // this.requestFrequency = 0;
                // }
                sendFileDataToPopup();
            }
                
        }
    }
    async enqueueProcessing() {
        clearInterval(initData.processingT)
        initData.processingT = setInterval(async ()=> {
            initData.loadFiles = await getSyncStorage("fileObj") || [];
            let isProcessing = initData.loadFiles.filter(item=> item.status == 1).map(item=>item.videoId);
            if(isProcessing.length == 0){
                clearInterval(initData.processingT);
                return;
            }
                try {
                    let res = await getProcessing(isProcessing);
                    let videos = res?.data?.videos;
                    if(videos){

                        if(!this.isInVideoQueue(isProcessing,videos)){
                            // 如果是false，证明请求的id与返回值不对应
                            isProcessing = [];
                        }
                        // 继续请求video
                        if(videos.length < this.maxQueueLength){
                            if(this.queue.length > 0){
                                this.maxQueue = false;
                                this.loadNextEnqueueVideo();
                            }else{
                                if(videos.length == 0){
                                    clearInterval(initData.processingT);
                                    // 全部完成
                                    return;
                                }
                            }
                        }else if(videos.length >= this.maxQueueLength){
                            this.maxQueue = true;
                        }
                        for(let item of videos){
                            if(item.status == 1 || item.status == 2){
                                // 生成中
                                if(item.percent && item.percent == 100){
                                    // 打开新页面
                                    const completeFile = initData.loadFiles.filter((file) => {
                                        if(file.videoId == item?.id){
                                            return file
                                        }
                                    })
                                    if(completeFile.length > 0){
                                        completeFile.forEach(file=>{
                                            file.status = 2;
                                        })
                                    }
                                    break;
                                }
                                if(item.videoURL){
                                    const completeFile = initData.loadFiles.filter((file) => {
                                        if(file.videoId == item?.id){
                                            return file
                                        }
                                    })
                                    if(completeFile.length > 0){
                                        completeFile.forEach(file=>{
                                            file.status = 2;
                                        })
                                    }
                                }
                            }else if(item.status == 11 || item.status == 12){
                                // 等待中
                                
                            }else if(item.status == 5){
                                // 不符合社区政策
                                const completeFile = initData.loadFiles.filter((file) => {
                                    if(file.videoId == item?.id){
                                        return file
                                    }
                                })
                                if(completeFile.length > 0){
                                    completeFile.forEach(file=>{
                                        file.status = 3;
                                    })
                                }
                            }else{
                                // 其他异常
                                const completeFile = initData.loadFiles.filter((file) => {
                                    if(file.videoId == item?.id){
                                        return file
                                    }
                                })
                                if(completeFile.length > 0){
                                    completeFile.forEach(file=>{
                                        file.status = 4;
                                    })
                                }
                            }
                        }
                        sendFileDataToPopup();
                    }
                } catch (error) {
                    clearInterval(initData.processingT);
                }
        },10000)
    }
    isInVideoQueue(isProcessing,resVideo){
        return isProcessing.some(function(bId) {
            return resVideo.some(function(aItem) {
                return aItem.id === bId;
            });
        });
    }
    async loadNextEnqueueVideo(){
        let queueItem = initData.loadFiles.find(item=> item.status == 0);
        if(queueItem){
            await this.enqueueVideo(queueItem);
        }else{
            // 没有数据了
        }
    }
}
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
async function uploadAllImg(filesArr, requestPolicyData) {
    setSyncStorage({ "filesUploaded": false });
    const promises = filesArr.map((fileObj, index) => {
        return new Promise((resolve, reject) => {
            setTimeout(async () => {
                try {
                    let arr = [];
                    var i = fileObj.forCount;
                    while (i > 0) {
                        i--
                        let timer = new Date().getTime();
                        await sleep(100);
                        if(fileObj.base64){
                            const loadFile = await processFileWithCache(fileObj, requestPolicyData);
                            loadFile.timer = timer;
                            arr.push(loadFile)
                        }else{    
                            let loadFile = {
                                id: CryptoJS.MD5(fileObj.id + fileObj.name + i).toString(),
                                moduleid: fileObj.moduleid,
                                sizeid: fileObj.sizeid,
                                timeid: fileObj.timeid,
                                videoId: null,
                                desc: fileObj.desc,
                                status:  0,
                                timer: timer
                            };
                            arr.push(loadFile)
                        }
                    } 
                    resolve(arr);
                } catch (error) {
                    reject(error);
                }
            }, index * 2000);
        }).catch(error => console.error("Error uploading file:", error));
    });
    try {
        const results = await Promise.all(promises);
        let flatResults = results.flat(Infinity);
        initData.loadFiles.push(...flatResults);
        console.log("uploadAllImg results:", initData.loadFiles);
        
        sendFileDataToPopup(true)
        return results;
    } catch (error) {
        console.log("uploadAllImg error:", error);
    }
}

const cache = new Map(); // 创建一个Map来保存缓存
async function processFileWithCache(fileObj, requestPolicyData) {
    const fileKey = getFileKey(fileObj);
    if (cache.has(fileKey)) {
        let loadFile = cache.get(fileKey);
        loadFile.desc = fileObj.desc;
        return JSON.parse(JSON.stringify(loadFile)); // 返回之前的结果
    }
    const { url, arrBuff, fname } = await putOss(fileObj, requestPolicyData);
    const fileID = await getPolicyCallback(fileObj, arrBuff.byteLength, requestPolicyData, fname);
    let loadFile = {
        id: fileObj.id,
        name: fileObj.name,
        type: fileObj.type,
        moduleid: fileObj.moduleid,
        sizeid: fileObj.sizeid,
        timeid: fileObj.timeid,
        imgUrl: url,
        fileID: fileID,
        videoId: null,
        desc: fileObj.desc,
        status: fileID ? 0 : -1,

    };
    // 将结果存入缓存
    cache.set(fileKey, loadFile);

    return JSON.parse(JSON.stringify(loadFile));
}
function getFileKey(fileObj) {
    // 根据fileObj生成唯一的key，这里只是一个示例，你需要根据实际情况调整
    return CryptoJS.MD5(fileObj.base64).toString();
}



async function getRequestPolicy() {
    let url = 'https://hailuoai.video/v1/api/files/request_policy';
    let headers = {
        'accept': 'application/json, text/plain, */*',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'token': initData.token,
    }
    let params = paramsInit()
    let queryString = Object.keys(params).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`).join('&');
    url += `?${queryString}`;
    const res = await fetchRequest(url, 'get', params, null, headers)
    return res;
}
async function putOss(fileObj, response) {
    const { bucketName, accessKeyId, accessKeySecret, dir, securityToken, endpoint } = response?.data
    let fname = generateImgName(fileObj.name);
    let url = `https://${bucketName}.${endpoint}/${dir}/${fname}`;
    let segment = `/${bucketName}/${dir}/${fname}`
    let t = getFromatTime(new Date, "UTC:ddd, dd mmm yyyy HH:MM:ss 'GMT'");
    let h = {
        "Content-Type": fileObj.type,
        "X-Oss-Date": t,
        "X-Oss-Security-Token": securityToken,
        "X-Oss-User-Agent": 'aliyun-sdk-js/6.20.0 Chrome 125.0.0.0 on Windows 10 64-bit'
    }

    let arrSign = ['PUT', '', h['Content-Type'], h['X-Oss-Date']]
    for (let k in h) {
        if (k.indexOf('X-Oss') != -1) {
            let str = k.toLocaleLowerCase() + ':' + h[k];
            arrSign.push(str);
        }
    }
    arrSign.push(segment);
    let strSign = arrSign.join('\n');
    

    let signature = CryptoJS.HmacSHA1(strSign, accessKeySecret);

    let base64 = signature.toString(CryptoJS.enc.Base64);

    h['Authorization'] = `OSS ${accessKeyId}:${base64}`;

    let fileBuf = base64ToBlob(fileObj.base64,fileObj.type);
    let arrBuff = await fileBuf.arrayBuffer();    
    await fetchRequest(url, 'PUT', {}, arrBuff, h);
    return {
        url, arrBuff, fname
    };
}

async function getPolicyCallback(fileData, byteLength, response, fname) {
    const { bucketName, accessKeyId, accessKeySecret, dir, securityToken, endpoint } = response?.data
    let urlOrigin = 'https://hailuoai.video/v1/api/files/policy_callback';
    let params = paramsInit()
    let queryString = Object.keys(params).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`).join('&');
    urlOrigin += `?${queryString}`;
    let data = {
        "fileName": fname,
        "originFileName": fileData.name,
        "dir": dir,
        "endpoint": endpoint,
        "bucketName": bucketName,
        "size": byteLength.toString(),
        "mimeType": fileData.type.split("/")[1],
        "fileScene": 10
    }

    let headers = {
        'accept': 'application/json, text/plain, */*',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'token': initData.token,
        'content-type': 'application/json'
    }
    const policyCallbackData = await fetchRequest(urlOrigin, 'POST', params, data, headers)
    let fileID = policyCallbackData?.data?.fileID;
    return fileID || '';
}

function geYy(url, body, params) {
    let queryString = Object.keys(params).map(key => `${key}=${params[key]}`).join('&');
    url += `?${queryString}`;
    let strBody = JSON.stringify(body)
    let md5Time = CryptoJS.MD5(String(params.unix)).toString()
    let s = `${encodeURIComponent(url)}_${strBody}${md5Time}ooui`;
    return CryptoJS.MD5(s).toString()
}

async function saveVideo(file,fileList) {
    let orgUrl = "/api/multimodal/generate/video";
    let url = `https://hailuoai.video/${orgUrl}`;
    let params = paramsInit()
    let queryString = Object.keys(params).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`).join('&');
    url += `?${queryString}`;
    let data = {
        'desc': file.desc,
        'useOriginPrompt': false,
        'fileList': fileList,
        'quantity': "1",
        'modelID': file.moduleid || "23001",
        'durationType': Number(file.timeid) || 1,
        'resolutionType': Number(file.sizeid) || 1,
    }
    if(file.moduleid == 23210){
        let descLen = file.desc.length;
        let promptStruct = {
                "value": [
                    {
                        "type": "paragraph",
                        "children": [
                            {
                                "text": file.desc
                            }
                        ]
                    }
                ],
                "length": descLen,
                "plainLength": descLen,
                "rawLength": descLen
            }
        data['extra'] = {
            "promptStruct": JSON.stringify(promptStruct),
            templateID: ""
        }
    }
    let headers = {
        'accept': 'application/json, text/plain, */*',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'token': initData.token,
        'content-type': 'application/json',
        'yy': geYy(orgUrl, data, params)
    }
    const res = await fetchRequest(url, 'POST', {}, data, headers);
    return res;
}

async function getProcessing(idList) {
    let orgUrl = "/api/multimodal/video/processing";
    let url = `https://hailuoai.video${orgUrl}`;
    let params = paramsInit()
    params.idList = encodeURIComponent(idList);
    let queryString = Object.keys(params).map(key => `${key}=${params[key]}`).join('&');
    url += `?${queryString}`;
    let headers = {
        'accept': 'application/json, text/plain, */*',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'token': initData.token,
        'content-type': 'application/json',
        'yy': geYy(orgUrl, {}, params)
    }
    const res = await fetchRequest(url, 'GET', {}, null, headers);
    return res;
}
async function getEquity() {
    let url = 'https://hailuoai.video/v1/api/user/equity';
    let headers = {
        'accept': 'application/json, text/plain, */*',
        'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'token': initData.token,
    }
    let params = paramsInit()
    let queryString = Object.keys(params).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`).join('&');
    url += `?${queryString}`;
    const res = await fetchRequest(url, 'get', {}, null, headers)
    return res?.data?.totalCredits;
}

function sendFileDataToPopup(filesUploaded = false) {
    setSyncStorage({ "fileObj": initData.loadFiles });
    if(filesUploaded){
        setSyncStorage({ "filesUploaded": filesUploaded });
    }
}
function paramsInit() {
    let strITime = Date.parse(new Date().toString());
    return {
        device_platform: 'web',
        app_id: 3001,
        version_code: 22202,
        lang: 'en',
        os_name: 'Windows',
        browser_name: getBrowserName(),
        device_memory: navigator.deviceMemory,
        cpu_core_num: navigator.hardwareConcurrency,
        browser_language: navigator.language,
        browser_platform: navigator.platform,
        screen_width: 1920,
        screen_height: 1080,
        unix: strITime
    }
}